%{
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <math.h>


/*
 * Definiciones de Cantidad Estados
 */

#define CANT_ESTADOS    35
#define CANT_SIMBOLOS   23

#define ESTADO_INICIAL   0

/*

/*Definicion de los tipos para el árbol*/
    
    
#define TIPOENTERO 0
#define TIPOLARGO 1
#define TIPOREAL 2
#define TIPODOBLE 3
#define TIPOTEXTO 4
#define MAXTIPOS 5

int fIg[MAXTIPOS][MAXTIPOS]={{0,-1,-1,-1,-1},{-1,1,-1,-1,-1},{-1,-1,2,-1,-1},{-1,-1,-1,3,-1},{-1,-1,-1,-1,4}};
int fMas[MAXTIPOS][MAXTIPOS]={{0,1,2,3,-1},{1,1,2,3,-1},{2,2,2,3,-1},{3,3,3,3,-1},{-1,-1,-1,-1,4}};
int fMenos[MAXTIPOS][MAXTIPOS]={{0,1,2,3,-1},{1,1,2,3,-1},{2,2,2,3,-1},{3,3,3,3,-1},{-1,-1,-1,-1,-1}};
int fMult[MAXTIPOS][MAXTIPOS]={{0,1,2,3,-1},{1,1,3,3,-1},{2,3,2,3,-1},{3,3,3,3,-1},{-1,-1,-1,-1,-1}};
int fDiv[MAXTIPOS][MAXTIPOS]={{0,1,2,3,-1},{1,1,2,3,-1},{2,2,2,3,-1},{3,3,3,3,-1},{-1,-1,-1,-1,-1}};


/* Definicion de Mínimos y Máximos.
 */

#define MAX_ID         30
#define MAX_STRING     50
#define MIN_CTE_REAL    -1.18e-38   
#define MAX_CTE_REAL    3.40e38 
#define CANT_PALABRAS_RESERVADAS 17
#define MAX_SIMBOLOS   500 
#define LONG_MAX_VAR 65

/******************************Declaracion variables de la TS**************************/

typedef struct{
               int posicion;
               char nombre[LONG_MAX_VAR];
               char tipo[LONG_MAX_VAR];
               char valor[LONG_MAX_VAR];
               int longitud;
               } RegistroTS;

RegistroTS TablaDeSimbolos[MAX_SIMBOLOS];
int CantSimbolos=0;
char CaracterLeido = '\0';
char CaracterAnterior = '\0';
int  yylval = 0;

char Contenido[LONG_MAX_VAR];

int TipoToken = 0;
int Indice = 0;
int Longitud = 0;

int ContComentario1 = 0;
int ContComentario2 = 0;

// Para imprimir la linea y columna de error.
int FilaE = 0;
int ColumnaE = 0;

FILE* ArchFuente;
FILE* ArchArbol;

char* palabras_reservadas[CANT_PALABRAS_RESERVADAS] =
{ "si", "ssi", "sino", "mientras", "que", "entonces", "inicio", "fin",
    "imprimir", "redondear", "truncar", "entero", "real",
    "texto", "enlista", "declaracion", "findedeclaracion" };
    
    

    

/******************************Fin declaracion variables de la TS**************************/


/******************************Funciones de la TS**************************/

int pilaVar[MAX_SIMBOLOS];
int topeVar=-1;

int BusquedaEnTS(char* Contenido)
{
    int ind;
    for (ind=0;ind<CantSimbolos;ind++)
        if (strcmp(TablaDeSimbolos[ind].nombre,Contenido) == 0)
                 return TablaDeSimbolos[ind].posicion;
    return -1;
}                 

int InsertarEnTS(RegistroTS registro)
{
    registro.posicion = CantSimbolos;
    strcpy(registro.tipo, "  ");
    registro.longitud = Longitud;
    TablaDeSimbolos[CantSimbolos] = registro;
    CantSimbolos++;
    
    return CantSimbolos-1;
}

void GrabarTS()
{
  FILE* TSimbolos;
  TSimbolos = fopen("TablaDeSimbolos.ts", "w+");
  
  int ind;
  fprintf(TSimbolos,"%-20s|%-20s|%-20s|%-20s|%-20s\n","POSICION","NOMBRE","TIPO","VALOR","LONGITUD");
  for(ind=0;ind<CantSimbolos;ind++)   
     fprintf(TSimbolos, "%-20d|%-20s|%-20s|%-20s|%-20d\n", TablaDeSimbolos[ind].posicion,TablaDeSimbolos[ind].nombre, TablaDeSimbolos[ind].tipo, TablaDeSimbolos[ind].valor, TablaDeSimbolos[ind].longitud);
  fclose(TSimbolos);   
}     


int apilarVariable (int var)
{
	topeVar++;	
	pilaVar[topeVar]=var;
	
  return var;
}


// desapilarvariable no es utilizada actualmente
int desapilarVariable (int var)
{
	
	var = pilaVar[topeVar];
	topeVar--;	

  return var;
}




void guardarTipos(char* tipo)
{
   while(topeVar != -1)
	{
	  strcpy(TablaDeSimbolos[pilaVar[topeVar]].tipo,tipo );
	  topeVar--;
	}
   
}	
/******************************fin de funciones de la TS**************************/



/************* definiciones y funciones de arbol *************/

// las hojas utilizan int pero los nodos utilizan char* hay que ver como resolverlo
// por ahora asigne dos valores dentro del t_nodo
typedef struct
{
  int   dato;
  char* datoChar;
  //char* tipo;

  int tipo;
  char  tipoNodo;

} t_dato;

typedef struct s_nodo
{
  t_dato datos;
  struct s_nodo *izq;
  struct s_nodo *der;

} t_nodo;

t_nodo * crear_nodo( char* contenido , t_nodo* izq , t_nodo* der )
{
     t_nodo * pNodo = (t_nodo *) malloc( 1 * sizeof(t_nodo) );

     if ( pNodo == NULL )
     {  
        printf("\nError: no es posible asignar memoria para generar el arbol de codigo intermedio.\n");
        exit(1);
     }
    
    pNodo -> datos.tipoNodo = 'n'; 
    pNodo -> datos.datoChar =  contenido;
    pNodo -> datos.dato = -1;

    pNodo-> izq = izq;
    pNodo-> der = der;
    if (der && izq)
	{
	   printf("**************************\nOperador en teoria (%s)\n", contenido);
		printf("tipo de la izquierda %d\n", izq->datos.tipo);
	   printf("tipo de la derecha %d\n*****************\n", der->datos.tipo);
  
	   if (strcmp( (char *) (contenido), "=")==0 || strcmp( (char *) (contenido), "==")==0 || strcmp( (char *) (contenido), "!=")==0)
               {
		pNodo -> datos.tipo=fIg[der->datos.tipo][izq->datos.tipo];
                printf ("Tipo del nodo %d \n",pNodo -> datos.tipo);
               }
	   if (strcmp( (char *) (contenido), "+")==0)
               {
		pNodo -> datos.tipo=fMas[der->datos.tipo][izq->datos.tipo];
                printf ("Tipo del nodo %d \n",pNodo -> datos.tipo);
               }
	   if (strcmp( (char *) (contenido), "-")==0 || strcmp( (char *) (contenido), "<")==0 || strcmp( (char *) (contenido), "<=")==0 || strcmp( (char *) (contenido), ">")==0 || strcmp( (char *) (contenido), ">=")==0 )
               {
		pNodo -> datos.tipo=fMenos[der->datos.tipo][izq->datos.tipo];
		printf ("Tipo del nodo %d \n",pNodo -> datos.tipo);
               }
           if (strcmp( (char *) (contenido), "*")==0)
               {
		pNodo -> datos.tipo=fMult[der->datos.tipo][izq->datos.tipo];
                printf ("Tipo del nodo %d \n",pNodo -> datos.tipo);
               }
           
	   if (strcmp( (char *) (contenido), "/")==0)
               {
		pNodo -> datos.tipo=fDiv[der->datos.tipo][izq->datos.tipo];
                printf ("Tipo del nodo %d \n",pNodo -> datos.tipo);
               }
	   if (strcmp( (char *) (contenido), "cuerpo")==0 )
               {
		pNodo -> datos.tipo=fIg[der->datos.tipo][izq->datos.tipo];
                printf ("Tipo del nodo en cuerpo %d \n",pNodo -> datos.tipo);
               }
	   if (strcmp( (char *) (contenido), "ssi")==0 )
               {
		pNodo -> datos.tipo=izq->datos.tipo;
                printf ("Tipo del nodo %d \n",pNodo -> datos.tipo);
               }
	    
  
	}	
    else 
	{
	   if (izq)
               {
                 pNodo -> datos.tipo = izq ->datos.tipo;
                 printf("NODO: solo nodo izq con tipo %d\n", izq->datos.tipo);
		}
           if (der)  
		{
			pNodo -> datos.tipo = der ->datos.tipo;
			printf("NODO solo nodo der con tipo %d\n", der->datos.tipo);
		}
	   if (!izq && !der)
		{
			pNodo -> datos.tipo = -2;
			//printf("son los dos nulos entonces le pongo -2 \n");
		}
           if (strcmp( (char *) (contenido), "redondear")==0 || strcmp( (char *) (contenido), "truncar")==0  )
               {
		pNodo -> datos.tipo=TIPOENTERO;
                printf ("Tipo del nodo %d \n",pNodo -> datos.tipo);
               }

        }
     if (pNodo -> datos.tipo == -1)
                   {
			printf ("Error al utilizar operador %s con distintos tipos\n",contenido);
			//exit(0);
		   }    
    return pNodo;
}

t_nodo * crear_hoja( int paramDato  )
{
     t_nodo * pHoja = (t_nodo *) malloc( 1 * sizeof(t_nodo) );

     if ( pHoja == NULL )
     {  
        printf("\nError: no es posible asignar memoria para generar el arbol de codigo intermedio.\n");
        exit(1);
     }
     
     pHoja -> datos.tipoNodo = 'h';
     pHoja -> datos.dato =  paramDato;
     pHoja -> datos.datoChar =  NULL;

      // asigna el tipo de dato a la estructura de nodo
      //strcpy (pHoja -> datos.tipo, ); 
      if (strcmp( TablaDeSimbolos[paramDato].tipo, "ENTERO") == 0 )
           pHoja-> datos.tipo = TIPOENTERO;
      else {
             if (strcmp( TablaDeSimbolos[paramDato].tipo, "REAL") == 0 )
                 pHoja-> datos.tipo = TIPOREAL;
             else {
			  if (strcmp( TablaDeSimbolos[paramDato].tipo, "TEXTO") == 0 )
           		  pHoja-> datos.tipo = TIPOTEXTO;
			  else {
				   printf("Error: %s no se encuentra definida en la zona de declaracion\n",TablaDeSimbolos[ paramDato].nombre);
				   exit(0);
				  }
			}
		}
					
     
     pHoja -> izq = pHoja -> der = NULL;
     
    return pHoja;
}

int numPasada = 0;

char * strrep(char *str, char old, char new)  {
    
    char *pos = NULL;
    pos = strchr(str, old);
    
    while ( pos != NULL )
    {
      *pos = new;
      pos = strchr(str, old);
    }
  
    return str;
}

char aux[30];

char * adecuarLatex( char *str )  {
       
    strcpy(aux, str);
    
    strrep(aux, '.', ',');
    
    strrep(aux, '_', '|');
  
    return aux;
}

char * adecuarTS( char *str )  {
    
    char *aux = str;
    
    while( *aux != '\0'){
            
        /* Verifico si '*aux' NO es letra o numero*/
        if ( !( 
              (*aux >= 'A' && *aux <= 'Z') || 
              (*aux >= 'a' && *aux <= 'z') || 
              (*aux >= '0' && *aux <= '9') 
              ) 
           )
        {
            *aux = '_';
        }

        aux++;
    }
    
      
    return str;
}

void mostrar( t_dato * paramDato) 
{
    
    if(paramDato)
    {
      if ( paramDato->tipoNodo == 'n' )
      {
          
          fprintf(ArchArbol ," .$%s$. ", adecuarLatex(paramDato -> datoChar) );
      }
      else
      {
          fprintf(ArchArbol ," .$%s$. ", adecuarLatex(TablaDeSimbolos[ paramDato -> dato ].nombre) );
      }
    }
    else
      fprintf(ArchArbol, "( .Programa. ");
}

void mostrar_preorden(t_nodo * arbol)
{
  
  if( arbol )
  {
    if ( arbol->der || arbol->izq )
        fprintf(ArchArbol ," ( ");
    
    mostrar( &arbol->datos );
     
    mostrar_preorden(arbol->izq);
    
    mostrar_preorden(arbol->der);
    
    if ( arbol->der || arbol->izq )
            fprintf(ArchArbol ," ) ");
    
  }

}

/*

void eliminar_arbol (t_nodo *arbol)
{
  if( arbol )
  {
    arbol_eliminar(arbol->izq);
    arbol_eliminar(arbol->der);
    free(arbol);
  }

}
*/

/************* fin de definiciones y funciones de arbol *************/


/******************* Pilas *******************/


typedef struct{

t_nodo * pila [MAX_SIMBOLOS];
int tope;

}t_pila;

t_pila pilaExpresion;

t_pila pilaSentencias;

t_pila pilaTermino;

t_pila pilaFactor;

t_pila  pilaCte;

t_pila pilaCondicion;

t_pila pilaCondiciones;

t_pila pilaId;


t_nodo *  Pcondiciones,
       *  Psentencia, 
       *  Pimprimir,
       *  Ptruncar,
       *  Predondear, 
       *  Pcadena_id, 
       *  Pdecision_ssi,  
       *  Pdecision,
       *  Piteracion, 
       *  Pasignacion, 
       *  Pprograma,
       *  PenLista;



t_nodo* apilar (t_pila * Ppila, t_nodo * nodo )
{
    
  Ppila->tope++;
  Ppila->pila[ Ppila->tope ]= nodo;  

  return Ppila->pila[ Ppila->tope ] ;
	
}

t_nodo* desapilar(t_pila * Ppila)
{
     t_nodo * nodo;
     nodo =  Ppila->pila[ Ppila->tope ];
     Ppila->tope--;
   
     return nodo;
}

int pilaVacia(t_pila * Ppila)
{
    int vacia = 0;

    if( Ppila->tope == -1 )
    {
        vacia = 1;
    }

    return vacia;
}


t_nodo * verPrimero ( t_pila * Ppila )
{       
    return  Ppila->pila[ Ppila->tope ];
}


void inicializarPila (t_pila * Ppila )
{
    Ppila-> tope = -1;
}



t_nodo * construirArbolDeAlcance()
{
    t_pila pilaAux;
    t_nodo * nodo_aux,* nodo_tope;
    t_nodo * sentencia;

    inicializarPila( &pilaAux );
    
    sentencia = desapilar( &pilaSentencias ) ;      

    while (  !pilaVacia( &pilaSentencias )  && strcmp( sentencia->datos.datoChar , "delimitadorDeAlcance" ) != 0  )
    {
        apilar( &pilaAux, sentencia );
        sentencia = desapilar( &pilaSentencias ) ;     
    }

    nodo_aux = crear_nodo( "LS", NULL , NULL );    

    nodo_tope = nodo_aux;

    while ( !pilaVacia( &pilaAux )  )
    {
        nodo_aux->izq = desapilar( &pilaAux );
      
        nodo_aux->der = crear_nodo( "LS", NULL , NULL );
        nodo_aux = nodo_aux->der;
  
    }
    
    return nodo_tope;
}


void delimitadorDeAlcance( t_pila * Ppila)
{
    t_nodo * nodo_aux = crear_nodo( "delimitadorDeAlcance" , NULL  , NULL  );
       
    apilar( Ppila, nodo_aux  )  ;
}


t_nodo * construirCadenaId( t_nodo * hoja )
{
    
    t_nodo * nodo_inferior = hoja , * nodo_aux ;

    nodo_aux = desapilar( &pilaId );
    nodo_inferior = crear_nodo( "=", nodo_aux , nodo_inferior );

    while ( !pilaVacia( &pilaId )  )
    {      
        
        nodo_aux = desapilar( &pilaId );
        
        if(nodo_aux != NULL)
            nodo_inferior = crear_nodo( "=", nodo_aux , nodo_inferior );

   
    } 
    
    return nodo_inferior;
    
}

// GENERADOR DE ASM


/*

typedef struct
{
  int   dato;
  char* datoChar;
  char* tipo;
  char  tipoNodo;

} t_dato;

typedef struct s_nodo
{
  t_dato datos;
  struct s_nodo *izq;
  struct s_nodo *der;

} t_nodo;

*/

char  Ruta[300];
FILE * ArchAsm;
int cantElemCopro=0;
int elemEnPilaMicro=0;
int  MAX_VUELCO_COPRO = 6;
int  cantCondicionales = 0;
int  cantEnLista = 0;

void imprimirASM ( t_nodo * );

void volcarCoproAMicro(void)
{       
     elemEnPilaMicro = 1;
     cantElemCopro = 0;
     fprintf( ArchAsm , ";-> pila llena - volcar copro a micro \n");
}

void volcarMicroACopro()
{
    elemEnPilaMicro = 0;
    cantElemCopro = MAX_VUELCO_COPRO;
    fprintf( ArchAsm , ";-> pila vacia - volcar micro a cobro \n");
}

void balanceoDePilas( void )
{
    if ( cantElemCopro >=  MAX_VUELCO_COPRO )
    {   
        volcarCoproAMicro();
    }

    if ( elemEnPilaMicro && cantElemCopro <= 0 )
    {   
        volcarMicroACopro();
    }

}

void hojaASM( t_nodo *  arbol )
{
    balanceoDePilas( );

    t_dato * aux = &(arbol->datos);
    
    if( strcmp(TablaDeSimbolos[ aux-> dato ].tipo, "TEXTO") != 0 )
        fprintf( ArchAsm , "fld qword [ %s ] \n",   TablaDeSimbolos[ aux-> dato ].nombre);
    else
        fprintf( ArchAsm , "AsignarCad txtaux, %s \n", TablaDeSimbolos[ aux-> dato ].nombre);
    
    cantElemCopro++;
}


void asignacionASM( t_nodo *  arbol )
{
    t_dato * datosIzq = &(arbol->izq->datos);
    t_dato * datosDer = &(arbol->der->datos);
    
    if( strcmp( TablaDeSimbolos[datosIzq->dato].tipo, "TEXTO" ) == 0 ){
        fprintf( ArchAsm , ";Igualo texto \n");
        
        if( arbol->der->datos.tipoNodo != 'h'  ){
            fprintf( ArchAsm , 
                    "AsignarCad %s, txtaux \n",
                    TablaDeSimbolos[datosIzq->dato].nombre
                );
        }
        else
        {
            fprintf( ArchAsm , 
                    "AsignarCad %s, %s \n",
                    TablaDeSimbolos[datosIzq->dato].nombre,
                    TablaDeSimbolos[datosDer->dato].nombre
                );
            
            fprintf( ArchAsm , 
                    "AsignarCad txtaux, %s \n",
                    TablaDeSimbolos[datosIzq->dato].nombre
                );
        }
        
    }
    else
    {
        if ( arbol->der->datos.tipoNodo == 'h' )
        {
            hojaASM( arbol->der);
            fprintf( ArchAsm , "fst qword [auxAsig]\n");
            fprintf( ArchAsm , "fstp qword [ %s ] ; Asignacion\n",  TablaDeSimbolos[ datosIzq-> dato ].nombre  );
            
        } else if ( strcmp(arbol->der->datos.datoChar, "=") == 0 ) {
            fprintf( ArchAsm , "fld qword [auxAsig]\n");
            fprintf( ArchAsm , "fstp qword [ %s ] ; Asignacion\n",  TablaDeSimbolos[ datosIzq-> dato ].nombre  );
        } else {
            fprintf( ArchAsm , "fstp qword [ %s ] ; Asignacion\n",  TablaDeSimbolos[ datosIzq-> dato ].nombre  );
        }
            

        
        cantElemCopro--;
    }

    

}


void sumaASM( t_nodo *  arbol )
{

    t_dato * datos = &(arbol->datos);
    
    t_dato * datosIzq = &(arbol->izq->datos);
    t_dato * datosDer = &(arbol->der->datos);

    if( strcmp( TablaDeSimbolos[datosIzq->dato].tipo, "TEXTO" ) == 0 ){
        
        fprintf( ArchAsm , 
                 ";Concatenacion %s + %s \n",
                 TablaDeSimbolos[datosIzq->dato].nombre,
                 TablaDeSimbolos[datosDer->dato].nombre );

        
        fprintf( ArchAsm , 
                 "Concatenar txtaux, %s, %s\n",
                 TablaDeSimbolos[datosIzq->dato].nombre,
                 TablaDeSimbolos[datosDer->dato].nombre);
        
    } else {
        
        if ( arbol->izq->datos.tipoNodo == 'h' )
        hojaASM( arbol->izq );

        if ( arbol->der->datos.tipoNodo == 'h' )
            hojaASM( arbol->der);

        fprintf( ArchAsm , "fadd \n");
        cantElemCopro--;
     
    }
  
    
}


void multiplicacionASM( t_nodo *  arbol )
{
    t_dato * aux = &(arbol->datos);

    if ( arbol->izq->datos.tipoNodo == 'h' )
        hojaASM( arbol->izq );

    if ( arbol->der->datos.tipoNodo == 'h' )
         hojaASM( arbol->der);

    fprintf( ArchAsm , "fmul \n");
    cantElemCopro--;
}

void divisionASM( t_nodo *  arbol )
{
    t_dato * aux = &(arbol->datos);

  
    if ( arbol->izq->datos.tipoNodo == 'h' )
        hojaASM( arbol->izq );

    if ( arbol->der->datos.tipoNodo == 'h' )
         hojaASM( arbol->der);

    if ( arbol->izq->datos.tipoNodo == 'h' &&  arbol->der->datos.tipoNodo == 'n' )
        fprintf( ArchAsm , "fxch\n");  

    fprintf( ArchAsm , "fdiv \n");
    cantElemCopro--;
}

void restaASM( t_nodo *  arbol )
{
    t_dato * aux = &(arbol->datos);

  
    if ( arbol->izq->datos.tipoNodo == 'h' )
        hojaASM( arbol->izq );

    if ( arbol->der->datos.tipoNodo == 'h' )
         hojaASM( arbol->der);

    if ( arbol->izq->datos.tipoNodo == 'h' &&  arbol->der->datos.tipoNodo == 'n' )
        fprintf( ArchAsm , "fxch\n");      

    fprintf( ArchAsm , "fsub \n");
    cantElemCopro--;

}

void truncarASM ( t_nodo *  arbol  )
{
    if ( arbol->izq->datos.tipoNodo == 'h' )
        hojaASM( arbol->izq );

    fprintf( ArchAsm , "truncar \n");
}

void redondearASM ( t_nodo *  arbol )
{
    if ( arbol->izq->datos.tipoNodo == 'h' )
        hojaASM( arbol->izq );

    fprintf( ArchAsm , "frndint \n");
}

t_nodo * IdEnLista;

void imprimirCondicional(char * tipoCondicion,
                         int invertirCond, 
                         int invertirSalto){
    int i = 0;
    
    char vecCondStr[6][4] = {">","<",">=","<=","!=","=="};
    char vecCondAsm[6][4] = {"ja","jb","jae","jbe","jne","je"};
    char vecCondAsmNeg[6][4] = {"jbe","jae","jb","ja","je","jne"};
    
    while( i < 6 && strcmp(tipoCondicion, vecCondStr[i]) != 0)
            i++;
        

    if( invertirCond != 1 ){
        
        if ( invertirSalto != 1 )
            fprintf(ArchAsm, "%s cond_verd_%d\n", vecCondAsm[i], cantCondicionales);
        else
            fprintf(ArchAsm, "%s cond_falso_%d\n", vecCondAsm[i], cantCondicionales);
        
    }
    else{        
        
        if ( invertirSalto != 1 )
            fprintf(ArchAsm, "%s cond_falso_%d\n", vecCondAsmNeg[i], cantCondicionales);
        else
            fprintf(ArchAsm, "%s cond_verd_%d\n", vecCondAsmNeg[i], cantCondicionales);
        
    }
    
    fprintf(ArchAsm, "fstp\nfstp\n");
    
    cantElemCopro = cantElemCopro - 2;
    
}

void evaluarCondicionASM( t_nodo *  Pcondicional, 
                          int invertirCond, 
                          int invertirSalto){ 
    
    
    char * tipoCondicion = Pcondicional->datos.datoChar;
    
    if ( strcmp(tipoCondicion, "enlista") != 0 &&
         strcmp(tipoCondicion, "constantes") != 0 ){
            
        
        if ( Pcondicional->der->datos.tipoNodo == 'h' ){
            hojaASM( Pcondicional->der );
        } else {
            if( strcmp(Pcondicional->der->datos.datoChar, "redondear") == 0 ) {
                redondearASM(Pcondicional->der);
            } else if ( strcmp(Pcondicional->der->datos.datoChar, "truncar") == 0 ) {
                truncarASM(Pcondicional->der);
            }
        }
        
        if ( Pcondicional->izq->datos.tipoNodo == 'h' ){
            hojaASM( Pcondicional->izq );
        } else {
            if( strcmp(Pcondicional->izq->datos.datoChar, "redondear") == 0 ) {
                redondearASM(Pcondicional->izq);
            } else if ( strcmp(Pcondicional->izq->datos.datoChar, "truncar") == 0 ) {
                truncarASM(Pcondicional->izq);
            }
        }
  
        
        
            
        fprintf(ArchAsm, "Comparar\n");
        
        imprimirCondicional(tipoCondicion,
                            invertirCond, 
                            invertirSalto);
        
        
    } /*EVALUO ENLISTA*/
    else if ( strcmp(tipoCondicion, "enlista") == 0 ) {
        fprintf(ArchAsm, ";enlista\n");
        
        IdEnLista = Pcondicional->izq;
        
        evaluarCondicionASM(Pcondicional->der, invertirCond, invertirSalto);
        
        if (invertirCond == 1 && invertirSalto == 0) /*Estoy en un AND*/
        {
            fprintf(ArchAsm, "jmp cond_falso_%d\n", cantCondicionales);
        } 
        
        fprintf(ArchAsm, "fin_enlista_%d: \n", cantEnLista);
        
        cantEnLista++;
        
    } else /*RECURSIVIDAD ENLISTA*/ {

        hojaASM(IdEnLista);
        hojaASM(Pcondicional->der);
        fprintf(ArchAsm, "Comparar\n");
        fprintf(ArchAsm, "fstp\nfstp\n");
        cantElemCopro = cantElemCopro - 2;
        
        if( invertirCond == 0 && invertirSalto == 0 ) /*Estoy en un OR*/
        {
            fprintf(ArchAsm, "je cond_verd_%d\n", cantCondicionales);
        } 
        else if (invertirCond == 1 && invertirSalto == 0) /*Estoy en un AND*/
        {
            fprintf(ArchAsm, "je fin_enlista_%d\n", cantEnLista);
        } 
        else if (invertirCond == 0 && invertirSalto == 1) /*Estoy en un NOT*/
        { 
            fprintf(ArchAsm, "je cond_falso_%d\n", cantCondicionales);
        }
        
        fprintf(ArchAsm, "fstp\nfstp\n");
        cantElemCopro = cantElemCopro - 2;
        
        if ( Pcondicional->izq->datos.datoChar == NULL ){
            
            hojaASM(IdEnLista);
            hojaASM(Pcondicional->der);
            fprintf(ArchAsm, "Comparar\n");
                        
            if( invertirCond == 0 && invertirSalto == 0 ) /*Estoy en un OR*/
            {
                fprintf(ArchAsm, "je cond_verd_%d\n", cantCondicionales);
            } 
            else if (invertirCond == 1 && invertirSalto == 0) /*Estoy en un AND*/
            {
                fprintf(ArchAsm, "je fin_enlista_%d\n", cantEnLista);
            } 
            else if (invertirCond == 0 && invertirSalto == 1) /*Estoy en un NOT*/
            { 
                fprintf(ArchAsm, "je cond_falso_%d\n", cantCondicionales);
            }
            
            fprintf(ArchAsm, "fstp\nfstp\n");
            cantElemCopro = cantElemCopro - 2;
            
        } else {
            
           evaluarCondicionASM(Pcondicional->izq, invertirCond, invertirSalto);
           
        }
            
        
    }
    
}

void imprimirCondicionASM( t_nodo *  Pcondicion )
{
    //fprintf( ArchAsm , ";Imprimir condiciones \n");
    t_nodo * condicionSuperior = Pcondicion->izq ;
    
    if( strcmp(condicionSuperior->datos.datoChar, "AND") == 0)
    {
        evaluarCondicionASM(condicionSuperior->izq, 1, 0);
        evaluarCondicionASM(condicionSuperior->der, 1, 0);
        
    } else if(strcmp(condicionSuperior->datos.datoChar, "OR") == 0) {
        
        evaluarCondicionASM(condicionSuperior->izq, 0, 0);
        evaluarCondicionASM(condicionSuperior->der, 0, 0);
        
        fprintf(ArchAsm, "jmp cond_falso_%d\n", cantCondicionales);
    
    } else if(strcmp(condicionSuperior->datos.datoChar, "!") == 0) {
        evaluarCondicionASM(condicionSuperior->izq, 0, 1);
    }
    else {
        evaluarCondicionASM(condicionSuperior, 1, 0);
    }
     
}


void impresionASM ( t_nodo *  arbol )
{

    RegistroTS datoImprimir = TablaDeSimbolos[ arbol->izq->datos.dato];
    
    if ( strcmp( datoImprimir.tipo, "TEXTO") == 0 ) 
        fprintf( ArchAsm , "ImprimirCadena %s\n", datoImprimir.nombre);
    else
        fprintf( ArchAsm , "ImprimirFlotante %s\n", datoImprimir.nombre);
    
}

void siASM (t_nodo * arbol  ,t_nodo * Pcondicion ,t_nodo * Pcuerpo )
{       

    int numCondicionalLocal = cantCondicionales;

    imprimirCondicionASM( Pcondicion );
    
    cantCondicionales++;

    fprintf( ArchAsm , "cond_verd_%d: \n", numCondicionalLocal );

    imprimirASM( Pcuerpo->izq );
    
    fprintf( ArchAsm , "jmp fin_cond_%d\n", numCondicionalLocal );

    fprintf( ArchAsm , "cond_falso_%d: \n", numCondicionalLocal );
    
    if ( Pcuerpo->der != NULL ) 
        imprimirASM( Pcuerpo->der );
    
        
    fprintf( ArchAsm , "fin_cond_%d: \n", numCondicionalLocal );
}


void ssiASM (t_nodo * arbol, t_nodo * Pcondicion, t_nodo * Pcuerpo)
{       
    
    int numCondicionalLocal = cantCondicionales;
    
    fprintf( ArchAsm , ";Inicio SSI %d\n", numCondicionalLocal ); 

    imprimirCondicionASM( Pcondicion );
    
    cantCondicionales++;

    fprintf( ArchAsm , "cond_verd_%d: \n", numCondicionalLocal );

    if( Pcuerpo->izq->datos.tipoNodo == 'n' )
        imprimirASM( Pcuerpo->izq );
    else
        hojaASM( Pcuerpo->izq );
        
    fprintf( ArchAsm , "jmp fin_cond_%d\n", numCondicionalLocal );

    fprintf( ArchAsm , "cond_falso_%d: \n", numCondicionalLocal );

    if( Pcuerpo->der->datos.tipoNodo == 'n' )
        imprimirASM( Pcuerpo->der );
    else
        hojaASM( Pcuerpo->der );
    
    fprintf( ArchAsm , "fin_cond_%d: \n", numCondicionalLocal );
    
    fprintf( ArchAsm , ";Fin SSI %d\n", numCondicionalLocal );

}

void mientrasASM (t_nodo * arbol , t_nodo * Pcondicion, t_nodo * Pcuerpo)
{
    
    int numCondicionalLocal = cantCondicionales;

    fprintf( ArchAsm , "inic_cond_%d: \n", numCondicionalLocal );
    
    imprimirCondicionASM( Pcondicion );
    
    cantCondicionales++;

    fprintf( ArchAsm , "cond_verd_%d: \n", numCondicionalLocal );

    imprimirASM( Pcuerpo->izq );
    
    fprintf( ArchAsm , "jmp inic_cond_%d\n", numCondicionalLocal );

    fprintf( ArchAsm , "cond_falso_%d: \n", numCondicionalLocal );  
    fprintf( ArchAsm , "fin_cond_%d: \n", numCondicionalLocal );

}


void imprimirASM( t_nodo *  arbol )
{

    if (  arbol && arbol->datos.tipoNodo == 'n'  )
    {
        char* datoCharNodo = (arbol->datos).datoChar ;
        t_nodo * Pcuerpo, *Pcondicion;
        
        // las siguientes lineas verifican si se ingreso a una condicion almacenando lo que se tiene a derecha y a izquierda
        //int cmpIzq = arbol->izq != NULL && arbol->izq->datos.tipoNodo == 'n'  ? strcmp( (arbol->izq->datos).datoChar , "condicion" ) == 0 : 0;
        //int cmpDer = arbol->der != NULL && arbol->der->datos.tipoNodo == 'n'  ? strcmp( (arbol->der->datos).datoChar , "cuerpo" ) == 0 : 0;

        if (  strcmp ( datoCharNodo, "si" ) == 0 ||
              strcmp ( datoCharNodo, "mientras" ) == 0 ||
              strcmp ( datoCharNodo, "ssi" ) == 0 )
        {
            Pcuerpo =  arbol->der;
            Pcondicion = arbol->izq;
        }
        else
        {
            imprimirASM( arbol->izq  );

            imprimirASM( arbol->der  );
        }
    
        //asignacion
        if (  strcmp( datoCharNodo , "=" ) == 0 )
        {
            asignacionASM( arbol );
        }

        //suma
        if (  strcmp(  datoCharNodo , "+" ) == 0 )
        {
            sumaASM( arbol );
        }

        //resta
        if (  strcmp(  datoCharNodo , "-" ) == 0 )
        {
            restaASM( arbol );
        }

        //multiplicacion
        if (  strcmp(  datoCharNodo , "*" ) == 0 )
        {
            multiplicacionASM( arbol );
        }

        //division
        if (  strcmp(  datoCharNodo , "/" ) == 0 )
        {
            divisionASM( arbol );
        }

        //truncar
        if (  strcmp(  datoCharNodo , "truncar" ) == 0 )
        {
            truncarASM( arbol );
        }

        //redondear
        if (  strcmp(  datoCharNodo , "redondear" ) == 0 )
        {
            redondearASM( arbol );
        }

        //imprimir
        if ( strcmp(  datoCharNodo , "imprimir" ) == 0 )
        {
            impresionASM( arbol );
        }


        //si
        if ( strcmp(  datoCharNodo , "si" ) == 0 )
        {
            siASM( arbol ,  Pcondicion ,Pcuerpo  );
        }

        //ssi  (if unario)
        if ( strcmp(  datoCharNodo , "ssi" ) == 0 )
        {
            ssiASM( arbol ,  Pcondicion ,Pcuerpo  );
        }


        //mientras
        if (  strcmp(  datoCharNodo , "mientras" ) == 0 )
        {
            mientrasASM( arbol , Pcondicion ,Pcuerpo  );
        }

      
    }
}

imprimirTablaDeSimbolos(){
    int i = 0;
    
    for( i = 0 ; i < CantSimbolos ; i++ ){

        if( strcmp(TablaDeSimbolos[i].tipo, "TEXTO") == 0 ){
            
            if ( strncmp(TablaDeSimbolos[i].nombre, "cte_", 4 ) == 0 )
            {
                fprintf(ArchAsm, 
                        "%s: db \"%s\",0\n", 
                        TablaDeSimbolos[i].nombre, 
                        TablaDeSimbolos[i].valor);
            }
            else
            {
                fprintf(ArchAsm, 
                        "%s: TIMES 50 db 0\n", 
                        TablaDeSimbolos[i].nombre);
            }
                
        }
        else{
            if( atof(TablaDeSimbolos[i].valor) != 0 ){
                fprintf(ArchAsm, 
                        "%s: dq %s\n", 
                        TablaDeSimbolos[i].nombre, 
                        TablaDeSimbolos[i].valor);
                
            }else{
                fprintf(ArchAsm, 
                        "%s: dq 0.0\n", 
                        TablaDeSimbolos[i].nombre, 
                        TablaDeSimbolos[i].valor);
            }
        }
        
    }
    
}

void generadorASM( t_nodo * Arbol  )
{

  ArchAsm = fopen( "salidaAsm.asm"  , "w");

  /*Cabecera del Archivo*/
  
  fprintf(ArchAsm,"global main\n"
                  "extern printf\n\n"
                  "section .data\n\n");

  fprintf(ArchAsm, "CadFlt:  db \"%%f\",10,0\n"
                   "CadStr:  db \"%%s\",10,0\n"
                   "aux:  dq 0.0\n"
                   "aux2:  dq 0.0\n"
                   "auxAsig:  dq 0.0\n"
                   "txtaux: TIMES 50 db 0\n\n");
  
  imprimirTablaDeSimbolos();
    
  fprintf(ArchAsm, 
    "\n\nsection .text\n\n"

    "%%macro truncar 0\n"
    "    fstcw [aux]\n"
    "    fwait\n"
    "    mov   ax, [aux]\n"
    "    or    ax,0c00h\n"
    "    mov   [aux2],ax\n"
    "    fldcw [aux2]\n"
    "    frndint\n"
    "    fldcw [aux]\n"
    "%%endmacro\n\n"

    "%%macro ImprimirFlotante 1\n\n"

    "    push  dword [%%1+4]\n"
    "    push  dword [%%1]\n"
    "    push  dword CadFlt\n\n"

    "    call printf\n\n"

    "    add esp, byte 12\n"
    "%%endmacro\n\n"

    "%%macro ImprimirCadena 1\n"
    "     push dword %%1\n"
    "     push dword CadStr\n"
    "     call printf\n"
    "     add  esp, byte 8\n"
    "%%endmacro\n\n"

    "%%macro Comparar 0\n"
    "     fcomp\n"
    "     fstsw ax\n"
    "     fwait\n"
    "     sahf\n"
    "%%endmacro\n\n"
    
    "_strlen:\n"
    "    mov  ecx, 0\n\n"
        
    "    inic_len:\n"
    "        cmp  byte [esi+ecx], 0\n"
    "        je   fin_len\n"
    "        inc  ecx\n"
    "        jmp inic_len\n"
    "    fin_len:\n\n"

    "    ret\n\n"

    ";Concatenar destino,cadena1,cadena2\n"
    "%%macro Concatenar 3\n"
    "     mov esi, %%2\n"
    "     mov edi, %%1\n"
    "     call _strlen\n"
    "     cld\n"
    "     rep movsb\n\n"

    "     mov esi, %%3\n"
    "     call _strlen\n"
    "     cld\n"
    "     rep movsb\n\n"

    "     mov eax, 0\n"
    "     mov [edi], eax\n"
    "%%endmacro\n\n"

    ";AsignarCad destino,cadena\n"
    "%%macro AsignarCad 2\n"
    "     mov esi, %%2\n"
    "     mov edi, %%1\n"
    "     call _strlen\n"
    "     cld\n"
    "     rep movsb\n\n"
        
    "     mov eax, 0\n"
    "     mov [edi], eax\n"
    "%%endmacro\n\n"

    " _start:\n"
    "     call main ;llama a la funcion principal\n\n"
        
    " _fin:\n"
    "     mov eax,1 ;llamada al sistema (sys_exit)\n"
    "     int 0x80  ;llamo al kernel\n"
    "     ret       ;retorna el control al llamador\n\n"

    " main:       ;tell linker entry point\n\n"
        
    );

  // impresion de codigo ASM
  
  imprimirASM( Arbol );

  fprintf(ArchAsm,"\n\n     ret");

  fclose (ArchAsm);

}


void generarPdfArbol(void)
{
  printf("Cerrando archivo LaTeX...");
  fclose(ArchArbol);
  printf("[OK]\n");
  
  printf("Generando grafico PDF del arbol...");
  system("pdflatex tree.tex > /dev/null");
  printf("[OK]\n");
}

%}

%%

%token ID;
%token CTE_NUM;
%token CTE_REAL;
%token CTE_STRING;
%token DECLARACION;
%token FINDEDECLARACION;
%token SI;
%token ENTONCES;
%token INICIO;
%token FIN ;
%token SINO;
%token ENLISTA;
%token SSI;
%token MIENTRAS;
%token QUE;
%token TRUNCAR;
%token REDONDEAR;
%token IMPRIMIR;
%token ENTERO;
%token REAL;
%token TEXTO;		
%token COMA;
%token DOS_PUNTOS;
%token FIN_DE_LINEA;
%token OP_COMP;
%token OP_ASIG;
%token OP_MENOR_IG;
%token OP_MENOR;
%token OP_MAYOR_IG;
%token OP_MAYOR;
%token OP_SUMA;
%token OP_RESTA;
%token OP_MULT;
%token OP_DIV;
%token OP_AND;
%token OP_OR;
%token OP_DIST;
%token OP_NEG;
%token PAR_ABRE;
%token PAR_CIERRA;
%token CORCH_ABRE;
%token CORCH_CIERRA;
//%token MENOSUNARIO;
%start programa_principal; 
     

// BNF CHECK

programa_principal : programa {printf("\n======================= \n  Compilacion Exitosa\n=======================\n"); mostrar_preorden( Pprograma );generarPdfArbol();printf("\n\n"); generadorASM( Pprograma ); } ;

programa : INICIO lista_sentencias FIN { Pprograma = crear_nodo ( "Programa"   ,construirArbolDeAlcance(), NULL ); printf("solo lista_sentencias \n"); } 
        | declaracion INICIO lista_sentencias FIN { Pprograma = crear_nodo (  "Programa"   , construirArbolDeAlcance() , NULL ); printf("Declaracion + lista_sentencias \n"); } ;                             

declaracion : DECLARACION lista_variables FINDEDECLARACION { GrabarTS(); printf("Declaracion \n"); } ;

lista_variables : variable { printf("Variable \n "); } 
		| lista_variables variable { printf("Variables declaradas \n "); } ; 

variable : ENTERO DOS_PUNTOS lista_id FIN_DE_LINEA { guardarTipos("ENTERO");printf("var enteros \n"); }  
		| REAL DOS_PUNTOS lista_id FIN_DE_LINEA { guardarTipos("REAL");printf("var reales \n"); } 
		| TEXTO DOS_PUNTOS lista_id FIN_DE_LINEA { guardarTipos("TEXTO");printf("var texto \n"); } ;

lista_id : ID { apilarVariable($1);}
	     | lista_id COMA ID { apilarVariable($3);};


lista_sentencias : sentencia  {  apilar( &pilaSentencias, Psentencia ) ;  printf("---SENTENCIA EXITOSA---\n"); } 
                 | lista_sentencias sentencia {  apilar( &pilaSentencias, Psentencia ) ; printf("---SENTENCIA EXITOSA---\n"); } ;


sentencia :   decision { Psentencia =  Pdecision; printf("Tengo sentencia si\n"); } 

            | iteracion { Psentencia =  Piteracion ; printf("Tengo sentencia mientras que \n"); } 

            | imprimir FIN_DE_LINEA { Psentencia = Pimprimir; printf("Tengo sentencia imprimir \n"); } 

            | asignacion FIN_DE_LINEA { Psentencia = Pasignacion; printf("Tengo sentencia asignacion \n "); } ;


decision  : SI  PAR_ABRE condiciones  PAR_CIERRA  ENTONCES INICIO lista_sentencias FIN { Pdecision = crear_nodo("si", desapilar(&pilaCondiciones), crear_nodo ( "cuerpo" , construirArbolDeAlcance() , NULL ) );printf("SI\n");}
          | SI PAR_ABRE condiciones PAR_CIERRA ENTONCES INICIO lista_sentencias FIN SINO { delimitadorDeAlcance(  &pilaSentencias ) ; } INICIO lista_sentencias FIN { Pdecision= crear_nodo("si",desapilar(&pilaCondiciones),crear_nodo("cuerpo",construirArbolDeAlcance(), construirArbolDeAlcance() )) ;printf("SI con SINO\n");} ;

iteracion : MIENTRAS QUE PAR_ABRE condiciones PAR_CIERRA ENTONCES INICIO lista_sentencias FIN  {Piteracion=crear_nodo("mientras", desapilar( &pilaCondiciones) , crear_nodo ( "cuerpo" ,construirArbolDeAlcance(), NULL) );printf("Iteracion\n");} ;

imprimir : IMPRIMIR PAR_ABRE expresion PAR_CIERRA { Pimprimir= crear_nodo("imprimir",desapilar( &pilaExpresion ),NULL);printf("imprimir\n");} ;

asignacion : cadena_id expresion {  Pasignacion=  construirCadenaId( desapilar( &pilaExpresion)  ) ;   /*Pasignacion=crear_nodo( "=", Pcadena_id , desapilar( &pilaExpresion ) );*/ printf("Asignacion\n");} ;

cadena_id : ID OP_ASIG {  apilar( &pilaId , crear_hoja ( $1 ) ); printf("cadena_id\n");  /*Pcadena_id = crear_hoja($1); printf("cadena_id\n");*/}
	  | cadena_id ID OP_ASIG {  apilar( &pilaId , crear_hoja ( $2 ) ); printf("cadena_id + =\n");  /*Pcadena_id = crear_nodo("=",Pcadena_id,crear_hoja($2));printf("cadena_id + =\n");*/} ;

expresion : termino                    {   apilar( &pilaExpresion, desapilar( &pilaTermino) );  printf("EXPRESION\n"); }
	  | expresion OP_SUMA termino  {   apilar( &pilaExpresion, crear_nodo("+",desapilar( &pilaExpresion ),desapilar(&pilaTermino) )) ; printf("Suma COMO EXPRESION\n"); }
	  | expresion OP_RESTA termino {   apilar( &pilaExpresion, crear_nodo("-",desapilar( &pilaExpresion ),desapilar(&pilaTermino) )) ; printf("Resta COMO EXPRESION\n"); } ;

termino :  factor                   {apilar(&pilaTermino, desapilar( &pilaFactor) ); printf("Factor COMO TERMINO\n");}
	   | termino OP_MULT factor {apilar(&pilaTermino, crear_nodo("*", desapilar(&pilaTermino), desapilar( &pilaFactor) )) ;printf("Multiplicacion COMO TERMINO\n");}
	   | termino OP_DIV factor  {apilar(&pilaTermino, crear_nodo("/",desapilar(&pilaTermino), desapilar( &pilaFactor) )) ;printf("Division COMO TERMINO\n");} ;

factor : PAR_ABRE expresion PAR_CIERRA { apilar( &pilaFactor, desapilar( &pilaExpresion) ); printf("Expr entre parentesis\n");}
       | ID  {  apilar( &pilaFactor, crear_hoja($1) );printf("ID COMO FACTOR\n"); }
       | CTE { apilar( &pilaFactor, crear_hoja( $1 ) ) ;printf("CTE COMO FACTOR\n"); }
       | decision_ssi { apilar( &pilaFactor, Pdecision_ssi );printf("SSI COMO FACTOR\n"); }
       | redondear {  apilar( &pilaFactor, Predondear );printf("Redondear COMO FACTOR\n"); }
       | truncar {  apilar( &pilaFactor, Ptruncar );printf("Truncar COMO FACTOR\n"); } ;

// NOSE COMO GUARDA VERDADERO Y FALSE - REVISAR
decision_ssi :  SSI PAR_ABRE condiciones COMA expresion COMA expresion PAR_CIERRA {Pdecision_ssi = crear_nodo("ssi",desapilar(&pilaCondiciones),crear_nodo("cuerpo",desapilar( &pilaExpresion ),desapilar( &pilaExpresion) ) ); construirArbolDeAlcance(); printf("SSI\n");} ;


condiciones : condicion { apilar( &pilaCondiciones,crear_nodo ( "condicion" , desapilar( &pilaCondicion ) , NULL ) ) ; printf("Condicion Simple\n"); delimitadorDeAlcance(  &pilaSentencias ); printf("DELIMITADOR INCLUIDO \n"); }
	    | condicion OP_AND condicion { apilar( &pilaCondiciones,crear_nodo ( "condicion" , crear_nodo( "AND", desapilar(&pilaCondicion), desapilar(&pilaCondicion) )  , NULL )) ;printf("Condicion AND\n"); delimitadorDeAlcance(  &pilaSentencias ); printf("DELIMITADOR INCLUIDO \n");   }
	    | condicion OP_OR condicion { apilar( &pilaCondiciones, crear_nodo ( "condicion" , crear_nodo( "OR", desapilar(&pilaCondicion), desapilar(&pilaCondicion) )  , NULL ) ) ;printf("Condicion OR\n");  delimitadorDeAlcance(  &pilaSentencias ); printf("DELIMITADOR INCLUIDO \n");} ;

condiciones : OP_NEG PAR_ABRE condicion PAR_CIERRA { apilar( &pilaCondiciones, crear_nodo ( "condicion" ,crear_nodo("!", desapilar(&pilaCondicion),NULL) , NULL  )); delimitadorDeAlcance(  &pilaSentencias ); printf("Condicion NEG\n");} ;



condicion : expresion OP_MAYOR expresion { apilar( &pilaCondicion, crear_nodo(">",desapilar( &pilaExpresion), desapilar( &pilaExpresion) ));printf("Condicion Mayor\n");}
	  | expresion OP_MAYOR_IG expresion { apilar( &pilaCondicion, crear_nodo(">=",desapilar( &pilaExpresion),desapilar( &pilaExpresion)));printf("Condicion Mayor Igual\n");}
	  | expresion OP_MENOR expresion {  apilar( &pilaCondicion, crear_nodo("<",desapilar( &pilaExpresion),desapilar( &pilaExpresion)));printf("Condicion Menor\n");}
	  | expresion OP_MENOR_IG expresion { apilar( &pilaCondicion, crear_nodo("<=",desapilar( &pilaExpresion),desapilar( &pilaExpresion)));printf("Condicion Menor Igual\n");}
	  | expresion OP_COMP expresion {  apilar(  &pilaCondicion,crear_nodo("==",desapilar( &pilaExpresion),desapilar( &pilaExpresion)));printf("Condicion Comparacion\n");}
	  | expresion OP_DIST expresion {  apilar( &pilaCondicion, crear_nodo("!=",desapilar(&pilaExpresion),desapilar( &pilaExpresion)));printf("Condicion Op Distinto\n");} 
    | ENLISTA PAR_ABRE ID FIN_DE_LINEA CORCH_ABRE constantes CORCH_CIERRA PAR_CIERRA { apilar( &pilaCondicion, crear_nodo("enlista", crear_hoja($3)  , desapilar( &pilaCte) )) ;printf("ENLISTA\n");} ;




truncar : TRUNCAR PAR_ABRE expresion PAR_CIERRA {Ptruncar=crear_nodo("truncar",desapilar(&pilaExpresion),NULL);printf("truncar\n");}  ;

redondear : REDONDEAR PAR_ABRE expresion PAR_CIERRA {Predondear=crear_nodo("redondear", desapilar(&pilaExpresion),NULL);printf("redondear\n");} ;


constantes : CTE { apilar( &pilaCte, crear_hoja( $1 ) ); printf("CONSTANTE\n"); } 
           | constantes FIN_DE_LINEA CTE { apilar (  &pilaCte , crear_nodo("constantes",  desapilar( &pilaCte ),  crear_hoja( $3 ) ) ) ; printf("Muchas Ctes.\n"); } ;


CTE :  CTE_NUM { strcpy(TablaDeSimbolos[$1].tipo,"ENTERO" );printf("CTE ENTERA\n");} 
     | CTE_REAL {strcpy(TablaDeSimbolos[$1].tipo,"REAL" );printf("CTE REAL \n")}
     | CTE_STRING {strcpy(TablaDeSimbolos[$1].tipo,"TEXTO" );printf("CTE DE TEXTO\n");} 

%%



int yyerror (char *s) {
    fprintf( stderr , "%s: En fila %d, columna %d\n",s , FilaE, ColumnaE);
}


int getEvento(char c)
{
  int ret = -1;

  /* Verifico si 'c' esta en el rango [A-Za-z] y devuelvo la columna 0 */
  if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
  {
    ret = 0;

    /* Verifico si 'c' esta en el rango [0-9] y devuelvo la columna 1 */
  }
  else if (c >= '0' && c <= '9')
  {

    ret = 1;

  }
  else
  {

    switch (c)
    {
    /**/
    case '.':
      ret = 2;
      break;
    case '@':
      ret = 3;
      break;
    case '=':
      ret = 4;
      break;
    case '<':
      ret = 5;
      break;
    case '>':
      ret = 6;
      break;
    case '+':
      ret = 7;
      break;
    case '-':
      ret = 8;
      break;
    case '*':
      ret = 9;
      break;
    case '/':
      ret = 10;
      break;
    case '(':
      ret = 11;
      break;
    case ')':
      ret = 12;
      break;
    case '\"':
      ret = 13;
      break;
    case '!':
      ret = 14;
      break;
    case '&':
      ret = 15;
      break;
    case '|':
      ret = 16;
      break;
    case ',':
      ret = 17;
      break;
    case ':':
      ret = 18;
      break;
    case '[':
      ret = 19;
      break;
    case ']':
      ret = 20;
      break;
    case ';':
      ret = 21;
      break;
    case '\n':
      ret = 22;
      break;
    case ' ':
      ret = 22;
      break;
    case '\t':
      ret = 22;
      break;
    case '\0':
      ret = 22;
      break;
    
    case EOF:
    break;

    default:
      printf("Caracter no reconocido: '%c'\n", c);

    }

  }

  return ret;
}

char* strlwr( char* s )
{
  char* p = s;
  while (*p = tolower( *p )) p++;
  return s;
}

char* strupper( char* s )
{
  char* p = s;
  while (*p = toupper( *p )) p++;
  return s;
}

void Inic_id()
{
  Indice = 0;
  memset(Contenido, '\0', sizeof(Contenido));
  Contenido[Indice++] = CaracterLeido;

  Longitud = 1;
}

void Cont_id()
{
  Contenido[Indice++] = CaracterLeido;
  Longitud++;

  if (Longitud > MAX_ID)
  {
    printf("\n Error, Nombre de identificador mayor a %d caracteres \n",
        MAX_ID );
    exit(1);
  }

}

void Fin_id()
{

  int palabra_reservada;  
  palabra_reservada = es_palabra_reservada();

  if ( palabra_reservada != -1 )
  {
    switch ( palabra_reservada )
    {
        case 0:
                TipoToken = SI;
                break;

        case 1:
                 TipoToken = SSI;
                 break;

        case 2:
                TipoToken = SINO;
                break;

        case 3:
                TipoToken = MIENTRAS;
                break;

        case 4:
                TipoToken = QUE;
                break;

        case 5:
                TipoToken = ENTONCES;
                break;

        case 6:
                TipoToken = INICIO;
                break;

        case 7:
                TipoToken = FIN;
                break;

        case 8:
                TipoToken = IMPRIMIR;
                break;

        case 9:
                TipoToken = REDONDEAR;
                break;

        case 10:
                TipoToken = TRUNCAR;
                break;

        case 11:
                TipoToken = ENTERO;
                break;

        case 12:
                TipoToken = REAL;
                break;

        case 13:
                TipoToken = TEXTO;
                break;

        case 14:
                TipoToken = ENLISTA;
                break;

        case 15:
                TipoToken = DECLARACION;
                break;

        case 16:
                TipoToken = FINDEDECLARACION;
                break;
    }

  

  }
  else
  {
    TipoToken = ID;

    //   llenar o agregar datos a la tabla de simbolos

    if((yylval = BusquedaEnTS(Contenido)) == -1)
         {
            RegistroTS registro;
            strcpy(registro.nombre, Contenido);
            strcpy(registro.valor, "");
            yylval = InsertarEnTS(registro);
         }


  }
}

void Inic_cte_num()
{
  Indice = 0;
  memset(Contenido, '\0', sizeof(Contenido));
  Contenido[Indice++] = CaracterLeido;
}

void Cont_cte_num()
{
  Contenido[Indice++] = CaracterLeido;
}

void Fin_cte_num()
{
  TipoToken = CTE_NUM;

  if (atof(Contenido) == HUGE_VAL || atof(Contenido) > MAX_CTE_REAL)
  {
    printf("\n Error, constante númerica entera menor al minimo representable:  %s \n", Contenido);
    exit(1);
  }

  if (atof(Contenido) == HUGE_VAL || atof(Contenido) < MIN_CTE_REAL) // VER ATOF: if(atof(token) != 0 && atof(token) < MIN_CTE_REAL) nose porque hace esto
  {
    printf("\n Error, constante númerica entera menor al minimo representable:  %s \n" , Contenido);
    exit(1);
  }

  //    llenar o agregar datos a la tabla de simbolos

    char nombreCte[ MAX_ID + 4 ] = "cte_";
    strcat( nombreCte , Contenido );
    adecuarTS(nombreCte);
    
    if((yylval = BusquedaEnTS(nombreCte)) == -1)
     {
        RegistroTS registro;
        strcpy(registro.nombre, nombreCte);
        strcpy(registro.valor, strcat( Contenido, ".00"));
        yylval = InsertarEnTS(registro);
     }

}

void Inic_cte_real()
{
  Indice = 0;
  memset(Contenido, '\0', sizeof(Contenido));
  Contenido[Indice++] = CaracterLeido;
}

void Cont_cte_real()
{
  Contenido[Indice++] = CaracterLeido;
}

void Fin_cte_real()
{
  TipoToken = CTE_REAL;

  if (atof(Contenido) == HUGE_VAL || atof(Contenido) > MAX_CTE_REAL)
  {
    printf("\n Error, constante númerica real mayor al maximo representable:  %s \n", Contenido);
    exit(1);
  }

  if (atof(Contenido) == HUGE_VAL || atof(Contenido) < MIN_CTE_REAL) // VER ATOF: if(atof(token) != 0 && atof(token) < MIN_CTE_REAL) nose porque hace esto
  {
    printf("\n Error, constante númerica real menor al minimo representable:   %s \n" , Contenido);
    exit(1);
  }

  //    llenar o agregar datos a la tabla de simbolos

  char nombreCte[ MAX_ID + 4 ] = "cte_";
  strcat( nombreCte , Contenido );
  adecuarTS(nombreCte);
    
  if((yylval = BusquedaEnTS(nombreCte)) == -1)
    {
        RegistroTS registro;
        
        strcpy(registro.nombre, nombreCte);

        if ( Contenido[0] == '.' ) 
        {
            char auxPunto[ MAX_ID ] = "0" ;
            strcpy ( Contenido, strcat( auxPunto , Contenido ) );
        }
                

        strcpy(registro.valor,strcat( Contenido, "0"));//le agrego un 0 por las dudas que termine en punto
        yylval = InsertarEnTS(registro);
    }
}



void Inic_fin_linea()
{
  Indice = 0;
  memset(Contenido, '\0', sizeof(Contenido));
  Contenido[Indice++] = CaracterLeido;
}

void Fin_linea()
{
  TipoToken = FIN_DE_LINEA;
}

void Inic_op_comp()
{
  Indice = 0;
  memset(Contenido, '\0', sizeof(Contenido));
  Contenido[Indice++] = CaracterLeido;
}

void Cont_op_comp()
{
  Contenido[Indice++] = CaracterLeido;
}

void Fin_op_comp()
{
  TipoToken = OP_COMP;
}

void Fin_op_asig()
{
  TipoToken = OP_ASIG;
}

void Inic_op_menor_ig()
{
  Indice = 0;
  memset(Contenido, '\0', sizeof(Contenido));
  Contenido[Indice++] = CaracterLeido;
}

void Cont_op_menor_ig()
{
  Contenido[Indice++] = CaracterLeido;
}

void Fin_op_menor_ig()
{
  TipoToken = OP_MENOR_IG;
}

void Fin_op_menor()
{
  TipoToken = OP_MENOR;
}

void Inic_op_mayor_ig()
{
  Indice = 0;
  memset(Contenido, '\0', sizeof(Contenido));
  Contenido[Indice++] = CaracterLeido;
}

void Cont_op_mayor_ig()
{
  Contenido[Indice++] = CaracterLeido;
}

void Fin_op_mayor_ig()
{
  TipoToken = OP_MAYOR_IG;
}

void Fin_op_mayor()
{
  TipoToken = OP_MAYOR;
}

void Inic_op_suma()
{
  Indice = 0;
  memset(Contenido, '\0', sizeof(Contenido));
  Contenido[Indice++] = CaracterLeido;
}

void Fin_op_suma()
{
  TipoToken = OP_SUMA;
}

void Inic_op_resta()
{
  Indice = 0;
  memset(Contenido, '\0', sizeof(Contenido));
  Contenido[Indice++] = CaracterLeido;
}

void Fin_op_resta()
{
  TipoToken = OP_RESTA;
}

void Inic_op_mult()
{
  Indice = 0;
  memset(Contenido, '\0', sizeof(Contenido));
  Contenido[Indice++] = CaracterLeido;
}

void Fin_op_mult()
{
  TipoToken = OP_MULT;
}

void Inic_op_div()
{
  Indice = 0;
  memset(Contenido, '\0', sizeof(Contenido));
  Contenido[Indice++] = CaracterLeido;
}

void Fin_op_div()
{
  TipoToken = OP_DIV;
}

int es_palabra_reservada()
{
  int i = 0 , numPalabraReservada = -1;

  while( numPalabraReservada == -1  && i < CANT_PALABRAS_RESERVADAS )
  {
    if ( strcmp( (char *) strlwr(Contenido), palabras_reservadas[i]) == 0 )
    {    
        numPalabraReservada = i; 
    }

    i++;
  }

  return numPalabraReservada;
}

void Inic_para()
{
  memset(Contenido, '\0', sizeof(Contenido));
  Indice = 0;
  Contenido[Indice++] = CaracterLeido;
}

void Fin_para()
{
  TipoToken = PAR_ABRE;
}

void Inic_parc()
{
  memset(Contenido, '\0', sizeof(Contenido));
  Indice = 0;
  Contenido[Indice++] = CaracterLeido;
}

void Fin_parc()
{
  TipoToken = PAR_CIERRA;
}

void Inic_corcha()
{
  memset(Contenido, '\0', sizeof(Contenido));
  Indice = 0;
  Contenido[Indice++] = CaracterLeido;
}

void Fin_corcha()
{
  TipoToken = CORCH_ABRE;
}

void Inic_corchc()
{
  memset(Contenido, '\0', sizeof(Contenido));
  Indice = 0;
  Contenido[Indice++] = CaracterLeido;
}

void Fin_corchc()
{
  TipoToken = CORCH_CIERRA;
}

void Inic_op_and()
{
  memset(Contenido, '\0', sizeof(Contenido));
  Indice = 0;
  Contenido[Indice++] = CaracterLeido;
}

void Cont_op_and()
{
  Contenido[Indice++] = CaracterLeido;
}

void Fin_op_and()
{
  TipoToken = OP_AND;
}

void Inic_op_or()
{
  memset(Contenido, '\0', sizeof(Contenido));
  Indice = 0;
  Contenido[Indice++] = CaracterLeido;
}

void Cont_op_or()
{
  Contenido[Indice++] = CaracterLeido;
}

void Fin_op_or()
{
  TipoToken = OP_OR;
}

void Inic_coma()
{
  memset(Contenido, '\0', sizeof(Contenido));
  Indice = 0;
  Contenido[Indice++] = CaracterLeido;
}

void Fin_coma()
{
  TipoToken = COMA;
}

void Inic_cte_string()
{
  memset(Contenido, '\0', sizeof(Contenido));
  Indice = 0;
  Longitud = 0;
}

void Cont_cte_string()
{
  if (CaracterLeido != '"')
  {
    Contenido[Indice++] = CaracterLeido;
    Longitud++;
  }
}

void Fin_cte_string()
{
    TipoToken = CTE_STRING;
    if (Longitud > MAX_STRING)
    {
    printf("\n Error, constante string mayor a %d caracteres\n", MAX_STRING);
    exit(1);
    }

    char nombreCte[ MAX_STRING + 5 ] = "cte_";
    strcat( nombreCte , Contenido );
    adecuarTS(nombreCte);
  
    if((yylval = BusquedaEnTS(nombreCte)) == -1)
    {
        RegistroTS registro;
        
        strcpy(registro.nombre, nombreCte );
        strcpy(registro.valor, Contenido);
        yylval = InsertarEnTS(registro);
    }

}

void Inic_op_dist()
{
  memset(Contenido, '\0', sizeof(Contenido));
  Indice = 0;
  Contenido[Indice++] = CaracterLeido;
}

void Cont_op_dist()
{
  Contenido[Indice++] = CaracterLeido;
}

void Fin_op_dist()
{
  TipoToken = OP_DIST;
}

void Inic_op_neg()
{
  memset(Contenido, '\0', sizeof(Contenido));
  Indice = 0;
  Contenido[Indice++] = CaracterLeido;
}

void Fin_op_neg()
{
  TipoToken = OP_NEG;
}

void Fin_dospuntos()
{
  TipoToken = DOS_PUNTOS;
}

void Comentario1()
{
  if (CaracterAnterior == ':' && CaracterLeido == '@')
    ContComentario1++;

  if (CaracterAnterior == '@' && CaracterLeido == ':')
    ContComentario1--;

  if (ContComentario1 > 0 && CaracterLeido == EOF)
  {
    printf(
        "Error, EOF dentro del primer nivel de comentario, comentario no balanceado \n");
    exit(1);
  }
}

void Comentario2()
{
  if (CaracterAnterior == ':' && CaracterLeido == '@')
    ContComentario2 = 1;

  if (CaracterAnterior == '@' && CaracterLeido == ':')
    ContComentario2--;

  if (ContComentario2 > 0 && CaracterLeido == EOF)
  {
    printf(
        "Error, EOF dentro del segundo nivel de comentario, comentario no balanceado \n");
    exit(1);
  }
}

void Error()
{

  printf("Error lexico \n");
  exit(1);
}

void Salta_caracter()
{
}
 
int NuevoEstado [CANT_ESTADOS][CANT_SIMBOLOS] =  {
 {1, 2, 34, -1, 5, 7, 9, 11, 12, 13, 14, 15, 16, 17, 19, 21, 23, 25, 26, 32, 33, 4, 0} ,
 {1, 1, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {35, 2, 3, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {35, 3, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {35, 35, 35, 35, 6, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {35, 35, 35, 35, 8, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {35, 35, 35, 35, 10, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 17, 17, 17, 17, 17, 17, 17, 17, 17} ,
 {35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {35, 35, 35, 35, 20, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, -1} ,
 {35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 24, -1, -1, -1, -1, -1, -1} ,
 {35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {35, 35, 35, 27, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {27, 27, 27, 28, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 29, 27, 27, 27, 27} ,
 {27, 27, 27, 28, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 27, 27, 27, 27} ,
 {27, 27, 27, 30, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 29, 27, 27, 27, 27} ,
 {30, 30, 30, 31, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30} ,
 {30, 30, 30, 31, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 27, 30, 30, 30, 30} ,
 {35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} ,
 {-1, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1} 
 };

void (*Procesos[CANT_ESTADOS][CANT_SIMBOLOS])() = { 
{Inic_id,Inic_cte_num,Inic_cte_real,Error,Inic_op_comp,Inic_op_menor_ig,Inic_op_mayor_ig,Inic_op_suma,Inic_op_resta,Inic_op_mult,Inic_op_div,Inic_para,Inic_parc,Inic_cte_string,Inic_op_dist,Inic_op_and,Inic_op_or,Inic_coma,Comentario1,Inic_corcha,Inic_corchc,Inic_fin_linea,Salta_caracter} ,  {Cont_id,Cont_id,Fin_id,Fin_id,Fin_id,Fin_id,Fin_id,Fin_id,Fin_id,Fin_id,Fin_id,Fin_id,Fin_id,Fin_id,Fin_id,Fin_id,Fin_id,Fin_id,Fin_id,Fin_id,Fin_id,Fin_id,Fin_id} ,  {Fin_cte_num,Cont_cte_num,Cont_cte_real,Fin_cte_num,Fin_cte_num,Fin_cte_num,Fin_cte_num,Fin_cte_num,Fin_cte_num,Fin_cte_num,Fin_cte_num,Fin_cte_num,Fin_cte_num,Fin_cte_num,Fin_cte_num,Fin_cte_num,Fin_cte_num,Fin_cte_num,Fin_cte_num,Fin_cte_num,Fin_cte_num,Fin_cte_num,Fin_cte_num} ,  {Fin_cte_real,Cont_cte_real,Fin_cte_real,Fin_cte_real,Fin_cte_real,Fin_cte_real,Fin_cte_real,Fin_cte_real,Fin_cte_real,Fin_cte_real,Fin_cte_real,Fin_cte_real,Fin_cte_real,Fin_cte_real,Fin_cte_real,Fin_cte_real,Fin_cte_real,Fin_cte_real,Fin_cte_real,Fin_cte_real,Fin_cte_real,Fin_cte_real,Fin_cte_real} ,  {Fin_linea,Fin_linea,Fin_linea,Fin_linea,Fin_linea,Fin_linea,Fin_linea,Fin_linea,Fin_linea,Fin_linea,Fin_linea,Fin_linea,Fin_linea,Fin_linea,Fin_linea,Fin_linea,Fin_linea,Fin_linea,Fin_linea,Fin_linea,Fin_linea,Fin_linea,Fin_linea} ,  {Fin_op_asig,Fin_op_asig,Fin_op_asig,Fin_op_asig,Cont_op_comp,Fin_op_asig,Fin_op_asig,Fin_op_asig,Fin_op_asig,Fin_op_asig,Fin_op_asig,Fin_op_asig,Fin_op_asig,Fin_op_asig,Fin_op_asig,Fin_op_asig,Fin_op_asig,Fin_op_asig,Fin_op_asig,Fin_op_asig,Fin_op_asig,Fin_op_asig,Fin_op_asig} ,  {Fin_op_comp,Fin_op_comp,Fin_op_comp,Fin_op_comp,Fin_op_comp,Fin_op_comp,Fin_op_comp,Fin_op_comp,Fin_op_comp,Fin_op_comp,Fin_op_comp,Fin_op_comp,Fin_op_comp,Fin_op_comp,Fin_op_comp,Fin_op_comp,Fin_op_comp,Fin_op_comp,Fin_op_comp,Fin_op_comp,Fin_op_comp,Fin_op_comp,Fin_op_comp} ,  {Fin_op_menor,Fin_op_menor,Fin_op_menor,Fin_op_menor,Cont_op_menor_ig,Fin_op_menor,Fin_op_menor,Fin_op_menor,Fin_op_menor,Fin_op_menor,Fin_op_menor,Fin_op_menor,Fin_op_menor,Fin_op_menor,Fin_op_menor,Fin_op_menor,Fin_op_menor,Fin_op_menor,Fin_op_menor,Fin_op_menor,Fin_op_menor,Fin_op_menor,Fin_op_menor} ,  {Fin_op_menor_ig,Fin_op_menor_ig,Fin_op_menor_ig,Fin_op_menor_ig,Fin_op_menor_ig,Fin_op_menor_ig,Fin_op_menor_ig,Fin_op_menor_ig,Fin_op_menor_ig,Fin_op_menor_ig,Fin_op_menor_ig,Fin_op_menor_ig,Fin_op_menor_ig,Fin_op_menor_ig,Fin_op_menor_ig,Fin_op_menor_ig,Fin_op_menor_ig,Fin_op_menor_ig,Fin_op_menor_ig,Fin_op_menor_ig,Fin_op_menor_ig,Fin_op_menor_ig,Fin_op_menor_ig} ,  {Fin_op_mayor,Fin_op_mayor,Fin_op_mayor,Fin_op_mayor,Cont_op_mayor_ig,Fin_op_mayor,Fin_op_mayor,Fin_op_mayor,Fin_op_mayor,Fin_op_mayor,Fin_op_mayor,Fin_op_mayor,Fin_op_mayor,Fin_op_mayor,Fin_op_mayor,Fin_op_mayor,Fin_op_mayor,Fin_op_mayor,Fin_op_mayor,Fin_op_mayor,Fin_op_mayor,Fin_op_mayor,Fin_op_mayor} ,  {Fin_op_mayor_ig,Fin_op_mayor_ig,Fin_op_mayor_ig,Fin_op_mayor_ig,Fin_op_mayor_ig,Fin_op_mayor_ig,Fin_op_mayor_ig,Fin_op_mayor_ig,Fin_op_mayor_ig,Fin_op_mayor_ig,Fin_op_mayor_ig,Fin_op_mayor_ig,Fin_op_mayor_ig,Fin_op_mayor_ig,Fin_op_mayor_ig,Fin_op_mayor_ig,Fin_op_mayor_ig,Fin_op_mayor_ig,Fin_op_mayor_ig,Fin_op_mayor_ig,Fin_op_mayor_ig,Fin_op_mayor_ig,Fin_op_mayor_ig} ,  {Fin_op_suma,Fin_op_suma,Fin_op_suma,Fin_op_suma,Fin_op_suma,Fin_op_suma,Fin_op_suma,Fin_op_suma,Fin_op_suma,Fin_op_suma,Fin_op_suma,Fin_op_suma,Fin_op_suma,Fin_op_suma,Fin_op_suma,Fin_op_suma,Fin_op_suma,Fin_op_suma,Fin_op_suma,Fin_op_suma,Fin_op_suma,Fin_op_suma,Fin_op_suma} ,  {Fin_op_resta,Fin_op_resta,Fin_op_resta,Fin_op_resta,Fin_op_resta,Fin_op_resta,Fin_op_resta,Fin_op_resta,Fin_op_resta,Fin_op_resta,Fin_op_resta,Fin_op_resta,Fin_op_resta,Fin_op_resta,Fin_op_resta,Fin_op_resta,Fin_op_resta,Fin_op_resta,Fin_op_resta,Fin_op_resta,Fin_op_resta,Fin_op_resta,Fin_op_resta} ,  {Fin_op_mult,Fin_op_mult,Fin_op_mult,Fin_op_mult,Fin_op_mult,Fin_op_mult,Fin_op_mult,Fin_op_mult,Fin_op_mult,Fin_op_mult,Fin_op_mult,Fin_op_mult,Fin_op_mult,Fin_op_mult,Fin_op_mult,Fin_op_mult,Fin_op_mult,Fin_op_mult,Fin_op_mult,Fin_op_mult,Fin_op_mult,Fin_op_mult,Fin_op_mult} ,  {Fin_op_div,Fin_op_div,Fin_op_div,Fin_op_div,Fin_op_div,Fin_op_div,Fin_op_div,Fin_op_div,Fin_op_div,Fin_op_div,Fin_op_div,Fin_op_div,Fin_op_div,Fin_op_div,Fin_op_div,Fin_op_div,Fin_op_div,Fin_op_div,Fin_op_div,Fin_op_div,Fin_op_div,Fin_op_div,Fin_op_div} ,  {Fin_para,Fin_para,Fin_para,Fin_para,Fin_para,Fin_para,Fin_para,Fin_para,Fin_para,Fin_para,Fin_para,Fin_para,Fin_para,Fin_para,Fin_para,Fin_para,Fin_para,Fin_para,Fin_para,Fin_para,Fin_para,Fin_para,Fin_para} ,  {Fin_parc,Fin_parc,Fin_parc,Fin_parc,Fin_parc,Fin_parc,Fin_parc,Fin_parc,Fin_parc,Fin_parc,Fin_parc,Fin_parc,Fin_parc,Fin_parc,Fin_parc,Fin_parc,Fin_parc,Fin_parc,Fin_parc,Fin_parc,Fin_parc,Fin_parc,Fin_parc} ,  {Cont_cte_string,Cont_cte_string,Cont_cte_string,Cont_cte_string,Cont_cte_string,Cont_cte_string,Cont_cte_string,Cont_cte_string,Cont_cte_string,Cont_cte_string,Cont_cte_string,Cont_cte_string,Cont_cte_string,Cont_cte_string,Cont_cte_string,Cont_cte_string,Cont_cte_string,Cont_cte_string,Cont_cte_string,Cont_cte_string,Cont_cte_string,Cont_cte_string,Cont_cte_string} ,  {Fin_cte_string,Fin_cte_string,Fin_cte_string,Fin_cte_string,Fin_cte_string,Fin_cte_string,Fin_cte_string,Fin_cte_string,Fin_cte_string,Fin_cte_string,Fin_cte_string,Fin_cte_string,Fin_cte_string,Fin_cte_string,Fin_cte_string,Fin_cte_string,Fin_cte_string,Fin_cte_string,Fin_cte_string,Fin_cte_string,Fin_cte_string,Fin_cte_string,Fin_cte_string} ,  {Fin_op_neg,Fin_op_neg,Fin_op_neg,Fin_op_neg,Cont_op_dist,Fin_op_neg,Fin_op_neg,Fin_op_neg,Fin_op_neg,Fin_op_neg,Fin_op_neg,Fin_op_neg,Fin_op_neg,Fin_op_neg,Fin_op_neg,Fin_op_neg,Fin_op_neg,Fin_op_neg,Fin_op_neg,Fin_op_neg,Fin_op_neg,Fin_op_neg,Fin_op_neg} ,  {Fin_op_dist,Fin_op_dist,Fin_op_dist,Fin_op_dist,Fin_op_dist,Fin_op_dist,Fin_op_dist,Fin_op_dist,Fin_op_dist,Fin_op_dist,Fin_op_dist,Fin_op_dist,Fin_op_dist,Fin_op_dist,Fin_op_dist,Fin_op_dist,Fin_op_dist,Fin_op_dist,Fin_op_dist,Fin_op_dist,Fin_op_dist,Fin_op_dist,Fin_op_dist} ,  {Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Cont_op_and,Error,Error,Error,Error,Error,Error,Error} ,  {Fin_op_and,Fin_op_and,Fin_op_and,Fin_op_and,Fin_op_and,Fin_op_and,Fin_op_and,Fin_op_and,Fin_op_and,Fin_op_and,Fin_op_and,Fin_op_and,Fin_op_and,Fin_op_and,Fin_op_and,Fin_op_and,Fin_op_and,Fin_op_and,Fin_op_and,Fin_op_and,Fin_op_and,Fin_op_and,Fin_op_and} ,  {Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Cont_op_or,Error,Error,Error,Error,Error,Error} ,  {Fin_op_or,Fin_op_or,Fin_op_or,Fin_op_or,Fin_op_or,Fin_op_or,Fin_op_or,Fin_op_or,Fin_op_or,Fin_op_or,Fin_op_or,Fin_op_or,Fin_op_or,Fin_op_or,Fin_op_or,Fin_op_or,Fin_op_or,Fin_op_or,Fin_op_or,Fin_op_or,Fin_op_or,Fin_op_or,Fin_op_or} ,  {Fin_coma,Fin_coma,Fin_coma,Fin_coma,Fin_coma,Fin_coma,Fin_coma,Fin_coma,Fin_coma,Fin_coma,Fin_coma,Fin_coma,Fin_coma,Fin_coma,Fin_coma,Fin_coma,Fin_coma,Fin_coma,Fin_coma,Fin_coma,Fin_coma,Fin_coma,Fin_coma} ,  {Fin_dospuntos,Fin_dospuntos,Fin_dospuntos,Comentario1,Fin_dospuntos,Fin_dospuntos,Fin_dospuntos,Fin_dospuntos,Fin_dospuntos,Fin_dospuntos,Fin_dospuntos,Fin_dospuntos,Fin_dospuntos,Fin_dospuntos,Fin_dospuntos,Fin_dospuntos,Fin_dospuntos,Fin_dospuntos,Fin_dospuntos,Fin_dospuntos,Fin_dospuntos,Fin_dospuntos,Fin_dospuntos} ,  {Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario2,Comentario1,Comentario1,Comentario1,Comentario1} ,  {Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1} ,  {Comentario1,Comentario1,Comentario1,Comentario2,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario1,Comentario2,Comentario1,Comentario1,Comentario1,Comentario1} ,  {Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2} ,  {Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario2,Comentario1,Comentario2,Comentario2,Comentario2,Comentario2} ,  {Fin_corcha,Fin_corcha,Fin_corcha,Fin_corcha,Fin_corcha,Fin_corcha,Fin_corcha,Fin_corcha,Fin_corcha,Fin_corcha,Fin_corcha,Fin_corcha,Fin_corcha,Fin_corcha,Fin_corcha,Fin_corcha,Fin_corcha,Fin_corcha,Fin_corcha,Fin_corcha,Fin_corcha,Fin_corcha,Fin_corcha} ,  {Fin_corchc,Fin_corchc,Fin_corchc,Fin_corchc,Fin_corchc,Fin_corchc,Fin_corchc,Fin_corchc,Fin_corchc,Fin_corchc,Fin_corchc,Fin_corchc,Fin_corchc,Fin_corchc,Fin_corchc,Fin_corchc,Fin_corchc,Fin_corchc,Fin_corchc,Fin_corchc,Fin_corchc,Fin_corchc,Fin_corchc} ,  {Error,Cont_cte_real,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error,Error}
};


int yylex()
{
  int estado = ESTADO_INICIAL;
  int estadoFinal = CANT_ESTADOS;
  int columna = 0;

  if ( CaracterLeido == EOF ){
        TipoToken = 0;
        estado = estadoFinal;
  }

  while (estado != estadoFinal)
  {

    // contabilizo filas y columnas leidas para informar errores
    if ( CaracterLeido != '\n' ) 
    {
      ColumnaE++;
      //printf("%c", CaracterLeido);
    }
    else
    {
      FilaE++;
      ColumnaE = 0;
      //printf("%c", CaracterLeido);
    }

    /*Obtengo la columna de la matriz*/
    columna = getEvento(CaracterLeido);

    if (columna >= 0)
    {
      /*Ejecuto la función correspondiente*/
      (*Procesos[estado][columna] )();

      estado = NuevoEstado[estado][columna];

      if ( estado != estadoFinal ){
        CaracterAnterior = CaracterLeido;
        CaracterLeido = (char) getc(ArchFuente);
      }
       

    }
    else
    {
      if ( feof(ArchFuente) )
        TipoToken = 0;
      else
        TipoToken = -1;
      
      estado = estadoFinal;
    }

  }

  return TipoToken;

}


int main(int argc, char *argv[])
{

    inicializarPila( & pilaExpresion );
    inicializarPila( & pilaSentencias );
    inicializarPila( & pilaTermino );
    inicializarPila( & pilaFactor );
    inicializarPila( & pilaCte );
    inicializarPila( & pilaCondicion );
    delimitadorDeAlcance(& pilaSentencias);
 
    int tipoToken = 0;


  /*Apertura de Archivo codigo fuente*/
   if ( argc > 1 ) 
   {
      strcpy( Ruta ,argv[1]) ;
      ArchFuente = fopen(Ruta, "r");
   }
   else 
   {
      strcpy( Ruta , "ejemplo.p") ;
      ArchFuente = fopen("ejemplo.p", "r");
   }

  ArchArbol = fopen("arbolLatex.tex", "w");

  printf("Abriendo Archivo %s...", Ruta );

  if (ArchFuente != NULL)
  {
    /*Confirmo que el archivo se abrio bien.*/
    printf("[OK]\n");

    
    if ( !feof( ArchFuente ) )
      yyparse();

  }
  else
  {
    printf("[MAL]\n");
    printf("Error de apertura de archivo.\n");
    exit (1);
  }

  if (TipoToken == -1)
  {
    printf("***************Error Léxico***************\n");
  }

  GrabarTS();

  /* Cierre de Archivos */

  printf("Cerrando archivo entrada...");
  fclose(ArchFuente);
  printf("[OK]\n");
  
  system("nasm -o salidaObj.o -f elf32 salidaAsm.asm && gcc -m32 -o prog salidaObj.o");
  
  return 0;
}





